home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1999 February / Macworld (1999-02).dmg / Cinema 4D GO demo / Gumption Plug-ins / Plug-ins / Freeware / SubMesh / SubMesh.cof
Text File  |  1998-03-09  |  11KB  |  564 lines

  1. /*
  2.     This plugin can be used to selectively subdivide a polygon mesh.
  3.     Select the desired region with the Points tool and let 'er rip...
  4.     Be sure to use Tools/Structure/Optimise afterwards to remove
  5.     redundant points and edges (with 5.003, I can do this automatically)
  6.     Send comments, praise, money :-) etc. to:
  7.     
  8.     Jim Hasselbrook
  9.     hassel@bellatlantic.net
  10.     
  11.     This software is provided free, AS IS. Feel free to modify it to suit your needs.
  12. */
  13.  
  14.  
  15.  
  16.  
  17.  
  18.  
  19. var p_alloc, e_alloc, t_alloc, q_alloc;
  20. var p_used, e_used, t_used, q_used;
  21.  
  22. /*
  23.     Calculate the required number of points/triangles/quads up front...    
  24.     SetXxx() is at least an order of magnitude faster than AddXxx()!
  25. */
  26.  
  27. estimate(obj)    // this is exact, actually
  28. {
  29.     var i, which_case;
  30.     var points_selected = FALSE;
  31.     
  32.     var pcount = obj->GetPointCount();    
  33.     var qcount = obj->GetQuadrangleCount();
  34.     var tcount = obj->GetTriangleCount();
  35.     
  36.     p_alloc = pcount; p_used = pcount;
  37.     e_alloc = 0; e_used = 0;
  38.     q_alloc = 0; q_used = 0;
  39.     t_alloc = 0; t_used = 0;
  40.     
  41.     var q = new(Quadrangle);
  42.     var t = new(Triangle);
  43.         
  44.     for (i=0; i<qcount; i++)
  45.     {
  46.         obj->GetQuadrangle(i,q);
  47.         
  48.         which_case = 0;
  49.         
  50.         if (obj->IsPointSelected(q->a)) which_case += 8;
  51.         if (obj->IsPointSelected(q->b)) which_case += 4;
  52.         if (obj->IsPointSelected(q->c)) which_case += 2;
  53.         if (obj->IsPointSelected(q->d)) which_case += 1;
  54.         
  55.         if (which_case > 0)
  56.         {
  57.             points_selected = TRUE;
  58.         }
  59.         
  60.         switch (which_case)
  61.         {
  62.             // less than two points selected -> no subdivided edges
  63.         case 0:        // xxxx
  64.         case 1:        // xxxD
  65.         case 2:        // xxCx
  66.         case 4:        // xBxx
  67.         case 8:        // Axxx            
  68.             // diagonally opposite points don't define an edge, either
  69.         case 5:        // xBxD            
  70.         case 10:    // AxCx
  71.             e_alloc += 4;
  72.             q_alloc += 1;
  73.             break;
  74.             
  75.             
  76.             // two points selected -> one subdivided edge
  77.         case 3:        // xxCD
  78.         case 6:        // xBCx
  79.         case 9:        // AxxD
  80.         case 12:    // ABxx
  81.             p_alloc += 1;
  82.             e_alloc += 7;
  83.             t_alloc += 3;
  84.             break;
  85.             
  86.             
  87.             // three points selected -> two subdivided edges
  88.         case 13:    // ABxD
  89.         case 7:        // xBCD
  90.         case 11:    // AxCD
  91.         case 14:    // ABCx
  92.             p_alloc += 3;
  93.             e_alloc += 11;
  94.             q_alloc += 1;
  95.             t_alloc += 4;
  96.             break;
  97.             
  98.             
  99.             // all points selected -> four subdivided edges
  100.         case 15:    // ABCD
  101.             p_alloc += 5;
  102.             e_alloc += 12;
  103.             q_alloc += 4;
  104.             break;
  105.         }
  106.     }
  107.     
  108.     for (i=0; i<tcount; i++)
  109.     {
  110.         obj->GetTriangle(i,t);
  111.         
  112.         which_case = 0;
  113.         
  114.         if (obj->IsPointSelected(t->a)) which_case += 4;
  115.         if (obj->IsPointSelected(t->b)) which_case += 2;
  116.         if (obj->IsPointSelected(t->c)) which_case += 1;
  117.         
  118.         if (which_case > 0)
  119.         {
  120.             points_selected = TRUE;
  121.         }
  122.         
  123.         switch (which_case)
  124.         {
  125.             // less than two points selected -> no subdivided edges
  126.         case 0:        // xxxx
  127.         case 1:        // xxC
  128.         case 2:        // xBx
  129.         case 4:        // Axx
  130.             e_alloc += 3;
  131.             t_alloc += 1;
  132.             break;
  133.             
  134.             
  135.             // two points selected -> one subdivided edge
  136.         case 3:        // xBC
  137.         case 5:        // AxC
  138.         case 6:        // ABx
  139.             p_alloc += 1;
  140.             e_alloc += 5;
  141.             t_alloc += 2;
  142.             break;
  143.             
  144.             // all points selected -> three subdivided edges
  145.         case 7:        // ABC
  146.             p_alloc += 3;
  147.             e_alloc += 9;
  148.             t_alloc += 4;
  149.             break;
  150.         }
  151.     }
  152.     return points_selected;
  153. }
  154.  
  155. /*
  156.     Create a new polygon object from the existing one; just fill in points and edges
  157. */
  158.  
  159. copyPoints(doc,obj) 
  160. {
  161.     var i, p;
  162.     var pcount = obj->GetPointCount();
  163.  
  164.     var newobj = doc->NewPolygonObject(stradd(obj->GetName()," copy"),obj->GetUp(),NULL,p_alloc,e_alloc,t_alloc,q_alloc);
  165.  
  166.     newobj->SetScale(obj->GetScale());
  167.     newobj->SetPosition(obj->GetPosition());
  168.     newobj->SetRotation(obj->GetRotation());
  169.  
  170.     for (i=0;i<pcount;i++) {
  171.         p = obj->GetPoint(i);
  172.         newobj->SetPoint(i,p);
  173.     }
  174.  
  175.     return newobj;
  176. }
  177.  
  178. /*
  179.     Just in case we've underestimated the number of points/edges/triangles/quads we need...
  180. */
  181.  
  182. addPoint(obj,p)
  183. {
  184.     if (p_used < p_alloc)
  185.     {
  186.         obj->SetPoint(p_used,p);
  187.     }
  188.     else    // shouldn't happen
  189.     {
  190.         if (p_used == p_alloc)
  191.         {
  192.             println("Need more points!");
  193.         }
  194.         obj->AddPoint(p);
  195.     }
  196.     return p_used++;
  197. }
  198.  
  199. addEdge(obj,a,b)
  200. {
  201.     if (e_used < e_alloc)
  202.     {
  203.         obj->SetEdge(e_used,a,b);
  204.     }
  205.     else    // shouldn't happen
  206.     {
  207.         if (e_used == e_alloc)
  208.         {
  209.             println("Need more edges!");
  210.         }
  211.         obj->AddEdge(a,b);
  212.     }
  213.     e_used++;
  214. }
  215.  
  216. addQuadrangle(obj,a,b,c,d)
  217. {
  218.     if (q_used < q_alloc)
  219.     {
  220.         obj->SetQuadrangle(q_used,a,b,c,d);
  221.     }
  222.     else    // shouldn't happen
  223.     {
  224.         if (q_used == q_alloc)
  225.         {
  226.             println("Need more quadrangles!");
  227.         }
  228.         obj->AddQuadrangle(a,b,c,d);
  229.     }
  230.     q_used++;
  231. }
  232.  
  233. addTriangle(obj,a,b,c)
  234. {
  235.     if (t_used < t_alloc)
  236.     {
  237.         obj->SetTriangle(t_used,a,b,c);
  238.     }
  239.     else    // shouldn't happen
  240.     {
  241.         if (t_used == t_alloc)
  242.         {
  243.             println("Need more triangles!");
  244.         }
  245.         obj->AddTriangle(a,b,c);
  246.     }
  247.     t_used++;
  248. }
  249.  
  250. subdivideQuad0(obj,a,b,c,d)    // no subdivided edges
  251. {
  252.     addEdge(obj,a,b);
  253.     addEdge(obj,b,c);
  254.     addEdge(obj,c,d);
  255.     addEdge(obj,d,a);
  256.     addQuadrangle(obj,a,b,c,d);
  257. }
  258.  
  259. subdivideQuad1(obj,a,b,c,d)    // one subdivided edge
  260. {
  261.     var pa = obj->GetPoint(a);
  262.     var pb = obj->GetPoint(b);
  263.     var pab = (pa+pb)/2.0;
  264.     
  265.     var ab = addPoint(obj,pab);
  266.     addEdge(obj,a,ab);
  267.     addEdge(obj,ab,b);
  268.     addEdge(obj,b,c);
  269.     addEdge(obj,c,d);
  270.     addEdge(obj,d,a);
  271.     addEdge(obj,ab,c);
  272.     addEdge(obj,ab,d);
  273.     addTriangle(obj,a,ab,d);
  274.     addTriangle(obj,ab,c,d);
  275.     addTriangle(obj,ab,b,c);
  276. }
  277.  
  278. subdivideQuad2(obj,a,b,c,d)    // two subdivided edges
  279. {
  280.     var pa = obj->GetPoint(a);
  281.     var pb = obj->GetPoint(b);
  282.     var pc = obj->GetPoint(c);
  283.     var pd = obj->GetPoint(d);
  284.     var pab = (pa+pb)/2.0;
  285.     var pbc = (pb+pc)/2.0;
  286.     var pmid = (pa+pb+pc+pd)/4.0;
  287.     
  288.     var ab = addPoint(obj,pab);
  289.     var bc = addPoint(obj,pbc);
  290.     var mid = addPoint(obj,pmid);
  291.     addEdge(obj,a,ab);
  292.     addEdge(obj,ab,b);
  293.     addEdge(obj,b,bc);
  294.     addEdge(obj,bc,c);
  295.     addEdge(obj,c,d);
  296.     addEdge(obj,d,a);
  297.     addEdge(obj,ab,mid);
  298.     addEdge(obj,bc,mid);
  299.     addEdge(obj,c,mid);
  300.     addEdge(obj,d,mid);
  301.     addEdge(obj,a,mid);
  302.     addQuadrangle(obj,ab,b,bc,mid);
  303.     addTriangle(obj,a,ab,mid);
  304.     addTriangle(obj,bc,c,mid);
  305.     addTriangle(obj,c,d,mid);
  306.     addTriangle(obj,d,a,mid);
  307. }
  308.  
  309. subdivideQuad4(obj,a,b,c,d)    // four subdivided edges
  310. {
  311.     var pa = obj->GetPoint(a);
  312.     var pb = obj->GetPoint(b);
  313.     var pc = obj->GetPoint(c);
  314.     var pd = obj->GetPoint(d);
  315.     var pab = (pa+pb)/2.0;
  316.     var pbc = (pb+pc)/2.0;
  317.     var pcd = (pc+pd)/2.0;
  318.     var pda = (pd+pa)/2.0;
  319.     var pmid = (pa+pb+pc+pd)/4.0;
  320.     
  321.     var ab = addPoint(obj,pab);
  322.     var bc = addPoint(obj,pbc);
  323.     var cd = addPoint(obj,pcd);
  324.     var da = addPoint(obj,pda);
  325.     var mid = addPoint(obj,pmid);
  326.     addEdge(obj,a,ab);
  327.     addEdge(obj,ab,b);
  328.     addEdge(obj,b,bc);
  329.     addEdge(obj,bc,c);
  330.     addEdge(obj,c,cd);
  331.     addEdge(obj,cd,d);
  332.     addEdge(obj,d,da);
  333.     addEdge(obj,da,a);
  334.     addEdge(obj,ab,mid);
  335.     addEdge(obj,bc,mid);
  336.     addEdge(obj,cd,mid);
  337.     addEdge(obj,da,mid);
  338.     addQuadrangle(obj,a,ab,mid,da);
  339.     addQuadrangle(obj,ab,b,bc,mid);
  340.     addQuadrangle(obj,mid,bc,c,cd);
  341.     addQuadrangle(obj,da,mid,cd,d);
  342. }
  343.  
  344. subdivideTri0(obj,a,b,c)    // no subdivided edges
  345. {
  346.     addEdge(obj,a,b);
  347.     addEdge(obj,b,c);
  348.     addEdge(obj,c,a);
  349.     addTriangle(obj,a,b,c);
  350. }
  351.  
  352. subdivideTri1(obj,a,b,c)    // one subdivided edge
  353. {
  354.     var pa = obj->GetPoint(a);
  355.     var pb = obj->GetPoint(b);
  356.     var pab = (pa+pb)/2.0;
  357.     
  358.     var ab = addPoint(obj,pab);
  359.     addEdge(obj,a,ab);
  360.     addEdge(obj,ab,b);
  361.     addEdge(obj,b,c);
  362.     addEdge(obj,c,a);
  363.     addEdge(obj,ab,c);
  364.     addTriangle(obj,a,ab,c);
  365.     addTriangle(obj,ab,b,c);
  366. }
  367.  
  368. subdivideTri3(obj,a,b,c)    // three subdivided edges
  369. {
  370.     var pa = obj->GetPoint(a);
  371.     var pb = obj->GetPoint(b);
  372.     var pc = obj->GetPoint(c);
  373.     var pab = (pa+pb)/2.0;
  374.     var pbc = (pb+pc)/2.0;
  375.     var pca = (pc+pa)/2.0;
  376.     
  377.     var ab = addPoint(obj,pab);
  378.     var bc = addPoint(obj,pbc);
  379.     var ca = addPoint(obj,pca);
  380.     addEdge(obj,a,ab);
  381.     addEdge(obj,ab,b);
  382.     addEdge(obj,b,bc);
  383.     addEdge(obj,bc,c);
  384.     addEdge(obj,c,ca);
  385.     addEdge(obj,ca,a);
  386.     addEdge(obj,ab,bc);
  387.     addEdge(obj,bc,ca);
  388.     addEdge(obj,ca,ab);
  389.     addTriangle(obj,a,ab,ca);
  390.     addTriangle(obj,ab,bc,ca);
  391.     addTriangle(obj,ab,b,bc);
  392.     addTriangle(obj,ca,bc,c);
  393. }
  394.  
  395. /*
  396.     Where the rubber meets the road...
  397. */
  398. subdivide(doc)
  399. {
  400.     var i, which_case;
  401.     var a,b,c,d;
  402.     
  403.     var obj=doc->FindFirstActiveObject();
  404.     
  405.     if(!obj || !instanceof(obj, PolygonObject)) 
  406.     {
  407.         TextDialog("Must select a polygon object!", DLG_OK);
  408.         return;
  409.     }
  410.     
  411.     if (!estimate(obj))
  412.     {
  413.         TextDialog("No points were selected!", DLG_OK);
  414.         return;
  415.     }
  416.     
  417.     var newobj = copyPoints(doc,obj);
  418.     
  419.     var qcount = obj->GetQuadrangleCount();
  420.     var tcount = obj->GetTriangleCount();
  421.     var num_faces = qcount+tcount;
  422.     var q = new(Quadrangle);
  423.     var t = new(Triangle);
  424.         
  425.     for (i=0; i<qcount; i++)
  426.     {
  427.         obj->GetQuadrangle(i,q);
  428.         
  429.         a = q->a; b = q->b; c = q->c; d = q->d;
  430.         
  431.         which_case = 0;
  432.         
  433.         if (obj->IsPointSelected(a)) which_case += 8;
  434.         if (obj->IsPointSelected(b)) which_case += 4;
  435.         if (obj->IsPointSelected(c)) which_case += 2;
  436.         if (obj->IsPointSelected(d)) which_case += 1;
  437.         
  438.         switch (which_case)
  439.         {
  440.             // less than two points selected -> no subdivided edges
  441.         case 0:        // xxxx
  442.         case 1:        // xxxD
  443.         case 2:        // xxCx
  444.         case 4:        // xBxx
  445.         case 8:        // Axxx            
  446.             // diagonally opposite points don't define an edge, either
  447.         case 5:        // xBxD            
  448.         case 10:    // AxCx
  449.             subdivideQuad0(newobj,a,b,c,d);
  450.             break;
  451.             
  452.             
  453.             // two points selected -> one subdivided edge
  454.         case 3:        // xxCD
  455.             subdivideQuad1(newobj,c,d,a,b);
  456.             break;
  457.             
  458.         case 6:        // xBCx
  459.             subdivideQuad1(newobj,b,c,d,a);
  460.             break;
  461.             
  462.         case 9:        // AxxD
  463.             subdivideQuad1(newobj,d,a,b,c);
  464.             break;
  465.             
  466.         case 12:    // ABxx
  467.             subdivideQuad1(newobj,a,b,c,d);
  468.             break;
  469.             
  470.             
  471.             // three points selected -> two subdivided edges
  472.         case 13:    // ABxD
  473.             subdivideQuad2(newobj,d,a,b,c);
  474.             break;
  475.             
  476.         case 7:        // xBCD
  477.             subdivideQuad2(newobj,b,c,d,a);
  478.             break;
  479.             
  480.         case 11:    // AxCD
  481.             subdivideQuad2(newobj,c,d,a,b);
  482.             break;
  483.             
  484.         case 14:    // ABCx
  485.             subdivideQuad2(newobj,a,b,c,d);
  486.             break;
  487.             
  488.             
  489.             // all points selected -> four subdivided edges
  490.         case 15:    // ABCD
  491.             subdivideQuad4(newobj,a,b,c,d);
  492.             break;
  493.         }
  494.         
  495.         StatusSetBar(i*100.0/num_faces, TRUE);    
  496.     }
  497.     
  498.     for (i=0; i<tcount; i++)
  499.     {
  500.         obj->GetTriangle(i,t);
  501.         
  502.         a = t->a; b = t->b; c = t->c;
  503.         
  504.         which_case = 0;
  505.         
  506.         if (obj->IsPointSelected(a)) which_case += 4;
  507.         if (obj->IsPointSelected(b)) which_case += 2;
  508.         if (obj->IsPointSelected(c)) which_case += 1;
  509.         
  510.         switch (which_case)
  511.         {
  512.             // less than two points selected -> no subdivided edges
  513.         case 0:        // xxxx
  514.         case 1:        // xxC
  515.         case 2:        // xBx
  516.         case 4:        // Axx
  517.             subdivideTri0(newobj,a,b,c);
  518.             break;
  519.             
  520.             
  521.             // two points selected -> one subdivided edge
  522.         case 3:        // xBC
  523.             subdivideTri1(newobj,b,c,a);
  524.             break;
  525.             
  526.         case 5:        // AxC
  527.             subdivideTri1(newobj,c,a,b);
  528.             break;
  529.             
  530.         case 6:        // ABx
  531.             subdivideTri1(newobj,a,b,c);
  532.             break;
  533.  
  534.             
  535.             // all points selected -> three subdivided edges
  536.         case 7:        // ABC
  537.             subdivideTri3(newobj,a,b,c);
  538.             break;
  539.         }
  540.     
  541.         StatusSetBar((i+qcount)*100.0/num_faces, TRUE);    
  542.     }
  543.     
  544.     // we will have a lot of redundant points/edges when this is done; Optimise!!!
  545.     
  546.     if (GetC4DVersion() < 5003)
  547.     {
  548.         TextDialog("Done. Please run Tools/Structure/Optimise before proceeding.", DLG_OK);
  549.     }
  550.     else
  551.     {
  552.         newobj->Optimize(TRUE,TRUE,TRUE,TRUE);    // I assume this is a 5.003 feature?
  553.     }
  554.     newobj->UpdateObject();
  555.     doc->ActivateObject(newobj);
  556.     doc->SendMessage(DOCUMENT_CHANGED);
  557.     StatusClear();
  558. }
  559.  
  560. main()
  561. {
  562.     RegisterMenuHook("Subdivide","subdivide");
  563. }
  564.